﻿using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using Tsanie.Mp3Tag;
using Tsanie.Properties;
using Tsanie.ShellExtension;
using Tsanie.ShellExtension.PropertySheet;
using Tsanie.ShellExtension.PropertySheet.UI;
using System.Drawing;

namespace Tsanie {
    [Guid("C4A6E55E-C1CA-44ef-BE87-B99CC94BD808")]
    [ComVisible(true), ExtensionFileTypes(".mp3", FindAssoc = true)]
    public class Mp3TagPropertySheet : PropertySheetBase {

        #region - Fields -

        private bool ischanged;
        private bool pictureChanged;
        private Encoding _encoding;

        private ID3v2 _tag;
        private string _title;
        private string _album;
        private string _artist;
        private string _track;
        private string _year;

        private Label label1;
        private TextBoxEx textTitle;
        private Label label2;
        private TextBoxEx textAlbum;
        private Label label3;
        private TextBoxEx textArtist;
        private Label label4;
        private TextBoxEx textTrack;
        private Label label5;
        private TextBoxEx textYear;
        private PictureBoxEx previewBox;
        private ComboBox comboEncoding;

        #endregion

        #region - .Ctor -

        public Mp3TagPropertySheet()
            : base() {
            _tag = null;
            ischanged = false;
            pictureChanged = false;
            this.Text = Lang.PageTitle;
        }

        #endregion

        #region - Private methods -

        private void LoadUI() {
            this.label1.Text = Lang.Title;
            this.textTitle.EmptyText = Lang.EmptyOrMulti;
            this.label2.Text = Lang.Album;
            this.textAlbum.EmptyText = Lang.EmptyOrMulti;
            this.label3.Text = Lang.Artist;
            this.textArtist.EmptyText = Lang.Empty;
            this.label4.Text = Lang.Track;
            this.textTrack.EmptyText = Lang.Empty;
            this.label5.Text = Lang.Year;
            this.textYear.EmptyText = Lang.Empty;
            if (this.Files.Count > 1) {   // 多文件
                this.comboEncoding.Items.Add(Encoding.Default.WebName);
                this.comboEncoding.SelectedIndex = 0;
                return;
            }
            new Thread(delegate() {
                EncodingInfo[] encs = Encoding.GetEncodings();
                for (int i = 0; i < encs.Length; i++) {
                    EncodingInfo enc = encs[i];
                    this.comboEncoding.Items.Add(new EncodingItem() { Name = enc.Name, CodePage = enc.CodePage });
                    if (enc.CodePage == Encoding.Default.CodePage)
                        this.comboEncoding.SelectedIndex = i;
                }
                if (this.comboEncoding.SelectedIndex == -1) {
                    this.comboEncoding.SelectedIndex = 0;
#if TRACE
                    Common.OutputDebugString("LoadUI(void):: Encoding selected to default.");
                } else {
                    Common.OutputDebugString("LoadUI(void):: {0} encoding(s) loaded.", this.comboEncoding.Items.Count);
#endif
                }
            }) { Name = "thread_loadEncodings" }.Start();
        }
        private void LoadFields() {
            textTitle.Text = _title = _tag.Title;
            textAlbum.Text = _album = _tag.Album;
            textArtist.Text = _artist = _tag.Artist;
            textTrack.Text = _track = _tag.Track;
            textYear.Text = _year = _tag.Year;
        }

        #endregion

        #region - Events -

        private void TagChanged(object sender, EventArgs e) {
            if (ischanged)
                return;
            this.Changed();
            ischanged = true;
#if TRACE
            Common.OutputDebugString("TagChanged(object, EventArgs):: '{0}' fields changed.", ((Control)sender).Name);
#endif
        }
        private void ImageChanged(object sender, EventArgs e) {
            this.Changed();
            pictureChanged = true;
#if TRACE
            Common.OutputDebugString("ImageChanged(object, EventArgs):: picture fields changed.");
#endif
        }
        private void EncodingChanged(object sender, EventArgs e) {
            EncodingItem item = (EncodingItem)this.comboEncoding.SelectedItem;
            _encoding = Encoding.GetEncoding(item.CodePage);
            _tag.Encoding = _encoding;
            LoadFields();
        }

        #endregion

        #region - Overrides -

        protected override string[] AllowExtensions { get { return new string[] { ".mp3" }; } }
        protected override bool AllowMultiFiles { get { return true; } }
        protected override void OnCreatePage() {
            base.OnCreatePage();
            InitComponent();
            LoadUI();
            _encoding = Encoding.Default;
            if (this.Files.Count > 1) {
                // 多个文件
                this.textTitle.Enabled = false;
                this.textAlbum.Enabled = false;
                this.textArtist.Enabled = false;
                this.textTrack.Enabled = false;
                this.textYear.Enabled = false;
                this.comboEncoding.Enabled = false;
#if TRACE
                Common.OutputDebugString("OnCreatePage(void):: Multifiles.");
#endif
            } else {
                TagBase tag = TagUtil.ReadTag(this.Files[0]);
                if (tag != null && tag is ID3v2) {
                    _tag = (ID3v2)tag;
                } else {
                    _tag = new ID3v2(this.Files[0]);
                }
                LoadFields();
                previewBox.ImageData = _tag.PictureData;
#if TRACE
                Common.OutputDebugString("OnCreatePage(void):: Load fields complete.");
#endif
                // 事件
                this.textTitle.TextChanged += new EventHandler(TagChanged);
                this.textAlbum.TextChanged += new EventHandler(TagChanged);
                this.textArtist.TextChanged += new EventHandler(TagChanged);
                this.textTrack.TextChanged += new EventHandler(TagChanged);
                this.textYear.TextChanged += new EventHandler(TagChanged);
                this.comboEncoding.SelectedIndexChanged += new EventHandler(EncodingChanged);
            }
            this.previewBox.ImageChanged += new EventHandler(ImageChanged);

        }
        protected override PropertySheetBase.NotifyResult OnApply() {
            if (!ischanged && !pictureChanged) {
#if TRACE
                Common.OutputDebugString("OnApply(void):: There's no change.");
#endif
                return NotifyResult.InvalidNoChangePage;
            }

            if (ischanged && _tag != null) { // 单个Mp3
                if (textTitle.Text != _title) {
                    _tag.Title = _title = textTitle.Text;
                }
                if (textAlbum.Text != _album) {
                    _tag.Album = _album = textAlbum.Text;
                }
                if (textArtist.Text != _artist) {
                    _tag.Artist = _artist = textArtist.Text;
                }
                if (textTrack.Text != _track) {
                    _tag.Track = _track = textTrack.Text;
                }
                if (textYear.Text != _year) {
                    _tag.Year = _year = textYear.Text;
                }
            }
            if (pictureChanged && previewBox.Image != null) {
                if (_tag != null) {  // 单个Mp3
                    _tag.PictureData = previewBox.ImageData;
                } else {
                    foreach (string file in this.Files) {
                        ID3v2 tag = TagUtil.ReadTag(file) as ID3v2;
                        if (tag == null)
                            tag = new ID3v2(file);
                        tag.PictureData = previewBox.ImageData;
                        tag.Write();
                    }
#if TRACE
                    Common.OutputDebugString("OnApply(void):: Multifiles save changes done.");
#endif
                }
            }
            if (_tag != null) {
                _tag.Write();
#if TRACE
                Common.OutputDebugString("OnApply(void):: Save changes done.");
#endif
            }

            // 已保存
            ischanged = false;
            pictureChanged = false;
            return NotifyResult.NoError;
        }

        #endregion

        #region - Designer -

        /// <summary>
        /// 初始化组件
        /// </summary>
        private void InitComponent() {
            this.previewBox = new PictureBoxEx();
            this.label1 = new Label();
            this.textTitle = new TextBoxEx();
            this.label2 = new Label();
            this.textAlbum = new TextBoxEx();
            this.label3 = new Label();
            this.textArtist = new TextBoxEx();
            this.label4 = new Label();
            this.textTrack = new TextBoxEx();
            this.label5 = new Label();
            this.textYear = new TextBoxEx();
            this.comboEncoding = new ComboBox();

            this.previewBox.SuspendLayout();
            this.SuspendLayout();
            // 
            // previewBox
            // 
            this.previewBox.BackColor = SystemColors.ControlDark;
            this.previewBox.Location = new Point(8, 8);
            this.previewBox.Size = new Size(this.Width - 16, this.Height - 91);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new Point(8, this.Height - 74);
            // 
            // textTitle
            // 
            this.textTitle.Location = new Point(62, this.Height - 77);
            this.textTitle.Name = "textTitle";
            this.textTitle.Size = new Size(this.Width - 70, 19);
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new Point(8, this.Height - 49);
            // 
            // textAlbum
            // 
            this.textAlbum.Location = new Point(62, this.Height - 52);
            this.textAlbum.Name = "textAlbum";
            this.textAlbum.Size = new Size(this.Width - 150, 19);
            // 
            // label3
            // 
            this.label3.AutoSize = true;
            this.label3.Location = new Point(8, this.Height - 24);
            // 
            // textArtist
            // 
            this.textArtist.Location = new Point(70, this.Height - 27);
            this.textArtist.Name = "textArtist";
            this.textArtist.Size = new Size(this.Width - 245, 19);
            // 
            // label4
            // 
            this.label4.AutoSize = true;
            this.label4.Location = new Point(this.Width - 173, this.Height - 24);
            // 
            // textTrack
            // 
            this.textTrack.Location = new Point(this.Width - 132, this.Height - 27);
            this.textTrack.Name = "textTrack";
            this.textTrack.Size = new Size(28, 19);
            // 
            // label5
            // 
            this.label5.AutoSize = true;
            this.label5.Location = new Point(this.Width - 98, this.Height - 24);
            // 
            // textYear
            // 
            this.textYear.Location = new Point(this.Width - 57, this.Height - 27);
            this.textYear.Name = "textYear";
            this.textYear.Size = new Size(49, 19);
            // 
            // comboEncoding
            // 
            this.comboEncoding.FormattingEnabled = true;
            this.comboEncoding.DropDownStyle = ComboBoxStyle.DropDownList;
            this.comboEncoding.Location = new Point(this.Width - 82, this.Height - 52);
            this.comboEncoding.Size = new Size(74, 20);
            // 
            // Mp3TagPropertySheet
            // 
            this.Controls.Add(this.previewBox);
            this.Controls.Add(this.textTitle);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.textAlbum);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.comboEncoding);
            this.Controls.Add(this.textArtist);
            this.Controls.Add(this.label3);
            this.Controls.Add(this.textTrack);
            this.Controls.Add(this.label4);
            this.Controls.Add(this.textYear);
            this.Controls.Add(this.label5);

            this.previewBox.ResumeLayout(false);
            this.ResumeLayout(false);
        }

        #endregion

    }

    class EncodingItem {
        public string Name;
        public int CodePage;
        public override string ToString() {
            return this.Name;
        }
    }
}
